<?php

namespace Lrental\FeeFormula;

use App\Http\Controllers\Asset\AssetHelper;
use App\Models\Order\OrderItem;

class FormulaCondition
{
    use AssetHelper;
    const KEY_CATEGORY = 'category';
    const KEY_SUBCATEGORY = 'sub_category';
    /**
     * @var string
     */
    private $conditionStr;
    /**
     * @var array
     */
    private $orRelations;

    const KEY_DURATION = "duration";


    public function __construct(string $conditionStr)
    {
        if (empty($conditionStr)) {
            throw new \Exception("criteria can not be empty");
        }
        $this->conditionStr = strtolower($conditionStr);
        $this->parse();
    }

    private function parse()
    {
        $this->orRelations = explode(" or ", $this->conditionStr);
    }


    private function _isTrue(string $subCriteria, OrderItem $item)
    {
        $rules = collect(explode(" and ", $subCriteria));
        return $rules->every(function ($rule) use ($subCriteria, $item) {
            $rentalable = $item->rentalable;
            $matches = [];
            preg_match('/(.*)([=|>|<|~|like])(.*)/', $rule, $matches);
            if (count($matches) == 0) {
                \Log::warning("无效匹配 $subCriteria");
                return false;
            }
            list($str, $key, $operator, $value) = $matches;
            $key = trim($key);
            $value = trim($value);
            $result = false;
            list($real, $value) = $this->smartKeyValue($key, $value, $item);
            switch ($operator) {
                case "=":
                    $result = $real == $value;
                    break;
                case "!=":
                    $result = $real != $value;
                    break;
                case ">":
                    $result = $real > $value;
                    break;
                case "<":
                    $result = $real < $value;
                    break;
                case "like":
                case "~":
                    $result = mb_strpos($value, $real) !== false;
                    break;
            }
            return $result;
        });
    }

    public function test(OrderItem $item): bool
    {
        return collect($this->orRelations)->some(function ($subCriteria) use ($item) {
            return $this->_isTrue($subCriteria, $item);
        });
    }

    private function smartKeyValue(string $key, $value, OrderItem $item): array
    {
        $rentalable = $item->rentalable;
        $compareFrom = $rentalable[$key];
        $compareTo = $value;
        switch ($key) {
            case self::KEY_DURATION:
                $compareFrom = $item->order->expect_duration;
                $compareTo = $this->convertDuration($value);
                break;
            case self::KEY_CATEGORY:
                $compareFrom = $rentalable->category_id;
                $compareTo = $this->getPrimaryCategoryByName($value)['id'];
                break;
            case self::KEY_SUBCATEGORY:
                $compareFrom = $rentalable->sub_category_id;
                // 这里有个隐患，如果二级分类找到多个，默认这里只取第一个，可能会和用户的意图不符
                // 后续需要改进
                $compareTo = $this->getSubCategoriesByName($value)->first()['id'];
                break;
        }
        return [$compareFrom, $compareTo];
    }

    /**
     * convert date description to number of days
     * @param $value 1， 1天， 1周， 1月， 1年
     */
    private function convertDuration($value)
    {
        if (is_numeric($value)) {
            return $value;
        }
        $_value = mb_substr($value, 0, -1);
        $unit = mb_substr($value, -1);

        switch ($unit) {
            case "周":
                $_value = $_value * 7;
                break;
            case "月":
                $_value = $_value * 30;
                break;
            case "年":
                $_value = $_value * 365;
                break;
            default:
                $_value = intval($_value);
                break;
        }
        return $_value;
    }
}
